package org.eclipse.moquette.parser.netty;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import org.eclipse.moquette.proto.messages.AbstractMessage;
import org.eclipse.moquette.proto.messages.ConnectMessage;

/**
 * 对ConnectMessage 进行编码，不要被代码中得变量名迷惑
 * Created by alex on 15-5-19.
 */
public class ConnectEncoder extends DemuxEncoder<ConnectMessage> {

    @Override
    protected void encode(ChannelHandlerContext ctx, ConnectMessage message, ByteBuf out) {

        ByteBuf staticHeaderBuff = ctx.alloc().buffer(12); //静态部分(可变头部)
        ByteBuf buff = ctx.alloc().buffer();
        ByteBuf variableHeaderBuff = ctx.alloc().buffer(12); //可变部分(payload部分)

        try {

            //这些应该输入可变头部啊 根据message中的值写入更好 不要固定死
            staticHeaderBuff.writeBytes(Utils.encodeString("MQIsdp"));

            //version 3.1 根据message中的值写入更好 不要固定死
            staticHeaderBuff.writeByte(0x03);

            //connection flags and string  开始编码connection flags 这是一个八位的字节 包括了
            //--------------------------------------------------------------------------------------------------------
            //   NAME | userNameFlag | password Flag | Will Retain | Will Qos |  Will Flag | clean session | Reserved
            //--------------------------------------------------------------------------------------------------------
            //   bit  |1                1                1              2           1            1            1
            //----------------------------------------------------------------------------------------------------------
            byte connectionFlags = 0;

            if (message.isCleanSession()) {
                connectionFlags |= 0x02;
            }

            if (message.isWillFlag()) {
                connectionFlags |= 0x04;
            }

            connectionFlags |= ((message.getWillQos() & 0x03) << 3);
            if (message.isWillRetain()){
                connectionFlags |= 0x020;
            }
            if (message.isPasswordFlag()) {
                connectionFlags |= 0x040;
            }
            if (message.isUserFlag()){
                connectionFlags |= 0x080;
            }

            staticHeaderBuff.writeByte(connectionFlags);

            //Keep alive timer  写入keep alive 定时器
            staticHeaderBuff.writeShort(message.getKeepAlive());

            //Variable part （其实是payload）   写入clientID
            if (message.getClientID() != null) {
                variableHeaderBuff.writeBytes(Utils.encodeString(message.getClientID()));
                if (message.isWillFlag()) { //如果有遗愿 可以写入Will_Topic Will_Message
                    variableHeaderBuff.writeBytes(Utils.encodeString(message.getWillTopic()));
                    variableHeaderBuff.writeBytes(Utils.encodeString(message.getWillMessage()));
                }
                //根据协议要求写入username password
                if (message.isUserFlag() && message.getUsername() != null){
                    variableHeaderBuff.writeBytes(Utils.encodeString(message.getUsername()));
                    if (message.isPasswordFlag() && message.getPassword() != null) {
                        variableHeaderBuff.writeBytes(Utils.encodeString(message.getPassword()));
                    }
                }
            }

            int variableHeaderSize = variableHeaderBuff.readableBytes();


            //这才是真正的固定头部
            //首先写入 messageType connect
            buff.writeByte(AbstractMessage.CONNECT << 4);
            //写入剩余部分的的长度值 12 是硬编码的值(staticHeaderBuff)
            buff.writeBytes(Utils.encodeRemainingLength(12 + variableHeaderSize));
            //存储可变头部和payload
            buff.writeBytes(staticHeaderBuff).writeBytes(variableHeaderBuff);
            out.writeBytes(buff);
        } finally {
            //ByteBuf 调用release() 释放内存
            staticHeaderBuff.release();
            buff.release();
            variableHeaderBuff.release();
        }
    }
}
